/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bff.bjj.ui.component;

import com.bff.bjj.ui.component.events.KeyTypedEvent;
import com.bff.bjj.ui.component.events.KeyTypedListener;
import com.bff.mpd.musicjukebox.ui.components.ArtistList;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Bill
 */
public abstract class BJJList extends MusicList {

    private static final int KEY_TIMEOUT = 2000;
    private boolean keyTyping;
    private long lastKeyTime = 0;
    private List<KeyTypedListener> keyTypedListeners;
    private int initial;

    public BJJList() {
        keyTypedListeners = new ArrayList<KeyTypedListener>();

        KeyListener[] keyListeners = getKeyListeners();

        for (int i = 0; i < keyListeners.length; i++) {
            removeKeyListener(keyListeners[i]);
        }

        addKeyListener(new ListSearcher());
    }


    public abstract void positionForKey(String keyTyped);

    /**
     * Used for positioning of non char stuff like page up/down, etc.
     * @param keyCode
     */
    public abstract void positionForCode(int keyCode);

    private class ListSearcher extends KeyAdapter {

        protected String key = "";

        public ListSearcher() {
        }

        @Override
        public void keyTyped(KeyEvent e) {
            if (!isKeyTyping()) {
                initial = getSelectedIndex();
                setKeyTyping(true);
                new Thread(new KeyTimeThread()).start();
            }

            char ch = e.getKeyChar();
            if (!Character.isLetterOrDigit(ch)) {
                positionForCode(ch);
                return;
            }

            if (getLastKeyTime() + KEY_TIMEOUT > System.currentTimeMillis()) {
                key = "";
            }

            setLastKeyTime(System.currentTimeMillis());

            key += Character.toLowerCase(ch);
            positionForKey(key);
        }
    }

    private class KeyTimeThread implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ArtistList.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (getLastKeyTime() + KEY_TIMEOUT < System.currentTimeMillis()) {
                    setKeyTyping(false);
                    break;
                }
            }
        }
    }

    private void fireKeyTypedEvent(KeyTypedEvent.TYPE_EVENT event, boolean change) {

        for (KeyTypedListener listener : keyTypedListeners) {
            listener.keyTyped(new KeyTypedEvent(this, event, change));
        }
    }

    public void addKeyTypedListener(KeyTypedListener listener) {
        keyTypedListeners.add(listener);
    }

    public void removeKeyTypedListener(KeyTypedListener listener) {
        keyTypedListeners.remove(listener);
    }

    public long getLastKeyTime() {
        return lastKeyTime;
    }

    public void setLastKeyTime(long lastKeyTime) {
        this.lastKeyTime = lastKeyTime;
    }

    public boolean isKeyTyping() {
        return keyTyping;
    }

    private void setKeyTyping(boolean b) {
        this.keyTyping = b;

        if (b) {
            fireKeyTypedEvent(KeyTypedEvent.TYPE_EVENT.TYPE_STARTED, false);
        } else {
            fireKeyTypedEvent(KeyTypedEvent.TYPE_EVENT.TYPE_ENDED, initial != getSelectedIndex());
        }
    }
}
